package be.kul.osgi.ds.myagent.message;

import java.io.IOException;
import java.util.ArrayList;

import be.kul.osgi.ds.messageservice.MessageObject;
import be.kul.osgi.ds.myagent.Commitment;
import be.kul.osgi.ds.myagent.MyAgent;
import be.kul.osgi.ds.myagent.Schedule;

public class ContractNetResponder implements BasicBehaviour {

	//private static int TIMEOUT = 5000;
	public FSM fsm;
	public MessageObject mes;
	public MyAgent agent;
	private String ID;
	public ArrayList<BasicBehaviour> todo;
	public int cost;
	
	public ContractNetResponder(MyAgent agent, String ID){
		fsm = new FSM(agent, ID);
		this.agent = agent;
		this.ID = ID;
		this.todo = new ArrayList<BasicBehaviour>();
		this.cost = 0;
	}
	
	@Override
	public void HandleMessage(MessageObject mo) {
		// TODO Auto-generated method stub
		if ((mo.getPerformative() == MessageObject.CFP)){
			fsm.handle(mo);
		}
		
		if((mo.getPerformative() == MessageObject.ACCEPT_PROPOSAL)){
			fsm.handle(mo);
		}
		
		if((mo.getPerformative() == MessageObject.REJECT_PROPOSAL)){
			fsm.changeState(2);
		}
		
		
	}
	
	@Override
	public boolean isInterested(MessageObject mo) {
		if (this.ID.equals(mo.getConversationId())){
			if ((mo.getPerformative() == MessageObject.CFP) && (fsm.current == 0)){
				return true;
			}
			
			if ((mo.getPerformative() == MessageObject.REJECT_PROPOSAL) && (fsm.current == 1)){
				return true;
			}
			
			if ((mo.getPerformative() == MessageObject.ACCEPT_PROPOSAL) && (fsm.current == 1)){
				return true;
			}
		}else {
			//System.out.println("ID's dont match : " + this.ID + " and " + mo.getConversationId());
		}
		return false;
	}

	
	
	public String getID(){
		return this.ID;
	}
	
	
	public class FSM {
		   // 2. States array
		   private State[] states  = { new HandleCFP(), new HandleAnswer(), new Done() } ;
		   
		   // 3. Current state
		   private int     current = 0;
		   
		   private MyAgent pagent;
		   private String ID;
		   public boolean rescheduling;
		   
		   public Commitment c;
		   // 4. Delegation and pass the this pointer
		   public void handle(MessageObject m)  { states[current].handle(  this , m); }
		   
		   public void changeState( int index ) { current = index; }
		   
		   
		   public FSM(MyAgent a, String ID){
			   pagent = a;
			   this.ID = ID;
			   rescheduling = false;
		   }
		   
		   public MyAgent getAgent(){
			   return pagent;
		   }
		   
		}

		// 5. The State base class
		abstract class State {
		   // 6. Default behavior
		   public void handle(  FSM fsm, MessageObject m ){
			   
		   }
		 }

		class HandleCFP extends State {
		   
			//handle what comes in after sending the CFP
			public void handle(  final FSM fsm, MessageObject m) { 
				//Analyze MessageObject
				//System.out.println(m.getContent());
				String task = agent.XMLStreamservice.Sub(m.getContent(), "Task");
				String state =  agent.XMLStreamservice.Sub(m.getContent(), "CState");
				//System.out.println(task);
				//System.out.println(state);
				//make a first commitment
				
				if(state != null && state.contains("")){
					fsm.c = new Commitment(task, state,agent);
				} else {
					fsm.c = new Commitment(task, agent);
				}
				
				synchronized(Schedule.sharedLock){
				
				if(agent.schedule.fit(fsm.c)){
//					try {
//						agent.schedule.add(c);
//					} catch (IOException e) {
//						// TODO Auto-generated catch block
//						e.printStackTrace();
//					}
					System.out.println("task fits");
				} else {
					fsm.rescheduling = true;
					ArrayList<Commitment> temp;
					try {
						temp = agent.schedule.reschedule(fsm.c);
						if(temp != null){
							//agent.schedule.sched = temp;
							cost = cost + 400;
						} else {
							cost = cost + 1000;
							//setup external rescheduling
							//add to todolist
						}
					} catch (IOException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}				
				//get cost for the scheduling
				
				}
				//get cost for downloading role & capabilities
				
				//capabilities
				ArrayList<String> deps = agent.XMLStreamservice.getValues(m.getContent(), "Dependency");
				for (String d:deps){
					if (!agent.BundleLookup(d)){
						System.out.println(d + "Bundle not present");
						cost = cost +100;
						todo.add(new AskCapability(agent.getMesID(), d, agent));
					} else {
						System.out.println(d + "Bundle present");
					}
				}
				
				//role
				String role = agent.XMLStreamservice.getRole(m.getContent());
				if (!agent.BundleLookup(role)){
					System.out.println("Role not present");
					cost = cost +200;
					todo.add(new AskRole(agent.getMesID(), role, agent));
				}
				
				//return the cost
				mes = new MessageObject(MessageObject.PROPOSE);
				//mes.setReplyByDate(new Date(System.currentTimeMillis()+TIMEOUT));
				
				mes.setReceiver(m.getSender());
				mes.setSender(agent.name);
				mes.setConversationId(ID);
				String cont =  Integer.toString(cost);
				mes.setContent(cont);
				String message = agent.getMessageService().serialize(mes);
				
				
				
				//start FSM
				agent.getComm().sendmulticast(message);
				fsm.changeState(1);
		    }
		
		}

		// 7. Only override some messages
		class HandleAnswer extends State {
		   
				@Override
		   		public void handle( FSM fsm, MessageObject m ) { 
					if ((m.getPerformative() == MessageObject.ACCEPT_PROPOSAL)){
						//send back 
						
						//add task
						synchronized(Schedule.sharedLock){
							try {
								if(fsm.rescheduling){
									ArrayList<Commitment> temp;
									temp = agent.schedule.reschedule(fsm.c);
									
									if (temp == null){
										if(!agent.schedule.add(fsm.c)){
											agent.schedule.addback(fsm.c);
										}
									} else {
										agent.schedule.sched = temp;
									}
								} else {
									String ID = fsm.getAgent().XMLStreamservice.getValue(fsm.c.xmlTask,"ID");
									System.out.println("add task, ID : " + ID);
									if (!agent.schedule.add(fsm.c)){
										agent.schedule.addback(fsm.c);
									}
								}
							} catch (IOException e) {
								// TODO Auto-generated catch block
								e.printStackTrace();
							}
						}
						//commit + make a callback to agent...
						synchronized (agent.messagehandler.bhs) {
							agent.messagehandler.bhs.addAll(todo);
						
							for(BasicBehaviour b:todo){
								b.start();
							}
						}
					} else if ((m.getPerformative() == MessageObject.REJECT_PROPOSAL)){
						fsm.changeState(2);
					} 
			   
			 }   
		}
		
		class Done extends State {
			   // 8. "call back to" the wrapper class
			   @Override
			public void handle( FSM fsm, MessageObject m ) { 
				   System.out.println( "@ContractInit, State Done!" );
			}   
		}

		@Override
		public void start() {
			// TODO Auto-generated method stub
			
		}
	
}
